package ldk.util.scrollviews

import android.content.Context
import android.graphics.Rect
import android.support.v4.view.*
import android.support.v4.widget.NestedScrollView
import android.support.v4.widget.ScrollerCompat
import android.support.v7.widget.RecyclerView
import android.util.AttributeSet
import android.util.Log
import android.view.*
import android.webkit.WebView

/**
 * 支持多个子view的ScrollView,
 * 用于嵌套多个可滑动的View
 * 首先准备支持两个子View
 * Created by ldkxingzhe@163.com on 2017/9/6.
 */
class TwoChildScrollView : ViewGroup,
        ScrollingView, NestedScrollingParent, NestedScrollingChild{
    companion object {
        private val TAG = "TwoChildScrollView"
        val DEBUG = true

        private val ANIMATED_SCROLL_GAP = 250
        private val MAX_SCROLL_FACTOR = 0.5f
        private val INVALID_POINTER = -1
    }

    private val mTempRect = Rect()
    private val mScroller: ScrollerCompat

    /**
     * Position of the last motion event
     * */
    private var mLastMotionY = 0

    private var mIsLayoutDirty = true
    private var mIsLaidOut = false

    private var mIsBeingDragged = false
    private var mVelocityTracker: VelocityTracker? = null

    private var mSmoothScrollingEnabled = true

    private var mTouchSlop: Int
    private var mMinimumVelocity: Int
    private var mMaximumVelocity: Int

    private var mActivePointerId = INVALID_POINTER

    private val mParentHelper: NestedScrollingParentHelper = NestedScrollingParentHelper(this)
    private val mChildHelper = NestedScrollingChildHelper(this)

    private var mNestedOffset: Int = 0
    private val mScrollOffset = IntArray(2)
    private val mScrollConsumed = IntArray(2)

    private var mLastFlingValue = 0

    var onScrollChanged: (()-> Unit)? = null


    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

    init {
        isNestedScrollingEnabled = true
        val configuration = ViewConfiguration.get(context)
        mTouchSlop = configuration.scaledTouchSlop
        mMinimumVelocity = configuration.scaledMinimumFlingVelocity
        mMaximumVelocity = configuration.scaledMaximumFlingVelocity
        descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
        mScroller = ScrollerCompat.create(context, null)
        setWillNotDraw(false)
    }

    override fun computeHorizontalScrollOffset(): Int {
        return super.computeHorizontalScrollOffset()
    }

    override fun computeHorizontalScrollRange(): Int {
        return super.computeHorizontalScrollRange()
    }

    override fun computeHorizontalScrollExtent(): Int {
        return super.computeHorizontalScrollExtent()
    }

    override fun computeVerticalScrollExtent(): Int {
        val result = measuredHeight
/*        if (DEBUG){
            Log.v(TAG, "computeVerticalScrollExtent($this), result is $result")
        }*/
        return result
    }

    override fun computeVerticalScrollOffset(): Int {
        val first = getChildAt(0)
        val second = getChildAt(1)
        var result = 0
        var firstOffset = 0
        var secondOffset = 0
        if (scrollY == 0){
            result =  computeViewVerticalScrollOffset(first)
        }else if (scrollY < first.measuredHeight){
            result =  computeViewVerticalScrollOffset(first) + scrollY
        }else{
            firstOffset = computeViewVerticalScrollRange(first)
            secondOffset = computeViewVerticalScrollOffset(second)
            result =  firstOffset + secondOffset
        }
/*        if (DEBUG){
            Log.v(TAG, "computeVerticalScrollOffset($this): result is $result, firstOffset is $firstOffset, secondOffset is $secondOffset")
        }*/
        return result
    }

    private fun computeViewVerticalScrollRange(view: View): Int{
        var result: Int
        if (view is ScrollingView){
            result = view.computeVerticalScrollRange()
        }else{
            val computeVerticalScrollRangeMethod = View::class.java.getDeclaredMethod("computeVerticalScrollRange")
            computeVerticalScrollRangeMethod.isAccessible = true
            result = computeVerticalScrollRangeMethod.invoke(view) as Int
        }
        return result
    }

    private fun computeViewVerticalScrollOffset(view: View): Int {
        var result: Int
        if (view is ScrollingView){
             result = view.computeVerticalScrollOffset()
        }else{
            val computeVerticalScrollOffsetMethod = View::class.java.getDeclaredMethod("computeVerticalScrollOffset")
            computeVerticalScrollOffsetMethod.isAccessible = true
            result =  computeVerticalScrollOffsetMethod.invoke(view) as Int
        }
        return result
    }

    override fun computeVerticalScrollRange(): Int {
        val first = getChildAt(0)
        val result = scrollRangeOfView(first) + scrollRangeOfView(getChildAt(1))
/*        if (DEBUG){
            Log.v(TAG, "computeVerticalScrollRange ($this): result is $result ")
        }*/
        return result
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val argumentException = {throw IllegalArgumentException("onlySupport EXACTLY")}
        assert(MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY, argumentException)
        assert(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY, argumentException)
        if (childCount != 2){
            throw IllegalStateException("only support two child")
        }

        val itemWidth = MeasureSpec.getSize(widthMeasureSpec)
        val itemHeight = MeasureSpec.getSize(heightMeasureSpec)
        val widthChildMeasureSpec = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY)
        val heightChildMeasureSpec = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.AT_MOST)
        val firstChild = getChildAt(0)
        val secondChild = getChildAt(1)
        firstChild.isVerticalScrollBarEnabled = false
        secondChild.isVerticalScrollBarEnabled = false
        firstChild.measure(widthChildMeasureSpec, heightChildMeasureSpec)
        secondChild.measure(widthChildMeasureSpec, heightChildMeasureSpec)
        setMeasuredDimension(itemWidth, itemHeight)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        val first = getChildAt(0)
        val second = getChildAt(1)
        first.layout(0, 0, width, first.measuredHeight)
        second.layout(0, first.measuredHeight, width, first.measuredHeight + second.measuredHeight)
    }

    private fun initOrResetVelocityTracker(){
        if (mVelocityTracker == null){
            mVelocityTracker = VelocityTracker.obtain()
        }else{
            mVelocityTracker!!.clear()
        }
    }

    private fun initVelocityTrackerIfNotExists(){
        if (mVelocityTracker == null){
            mVelocityTracker = VelocityTracker.obtain()
        }
    }

    private fun recycleVelocityTracker(){
        if (mVelocityTracker != null){
            mVelocityTracker!!.recycle()
            mVelocityTracker = null
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        val action = ev!!.action
        if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged){
            return true
        }

        when(action and MotionEventCompat.ACTION_MASK){
            MotionEvent.ACTION_MOVE-> run {
                val actionPointerId = mActivePointerId
                if (actionPointerId == INVALID_POINTER){
                    return@run
                }
                val pointerIndex = ev.findPointerIndex(actionPointerId)
                if (pointerIndex == -1){
                    Log.e(TAG, "Invalid pointerId=$actionPointerId in onInterceptTouchEvent")
                    return@run
                }

                val y = ev.getY(pointerIndex)
                val yDiff = Math.abs(y - mLastMotionY)
                if (yDiff > mTouchSlop && (nestedScrollAxes and ViewCompat.SCROLL_AXIS_VERTICAL) == 0){
                    mIsBeingDragged = true
                    mLastMotionY = y.toInt()
                    initVelocityTrackerIfNotExists()
                    mVelocityTracker!!.addMovement(ev)
                    mNestedOffset = 0
                    if (parent != null){
                        parent.requestDisallowInterceptTouchEvent(true)
                    }
                }
            }
            MotionEvent.ACTION_DOWN-> run {
                val y = ev.y.toInt()
                //TODO inChild() 判断
                mLastMotionY = y
                mActivePointerId = ev.getPointerId(0)
                initOrResetVelocityTracker()
                mVelocityTracker!!.addMovement(ev)
                /*
                 * If being flinged and user touches the screen, initiate drag;
                 * otherwise don't. mScroller.isFinished should be false when
                 * being flinged. We need to call computeScrollOffset() first so that
                 * isFinished() is correct.
                 */
                mScroller.computeScrollOffset()
                mIsBeingDragged = !mScroller.isFinished
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
                return@run
            }

            MotionEvent.ACTION_CANCEL,
            MotionEvent.ACTION_UP ->{
                /* Release the drag */
                mIsBeingDragged = false
                mActivePointerId = INVALID_POINTER
                recycleVelocityTracker()
                if (mScroller.springBack(scrollX, scrollY, 0,
                        0, 0, getScrollRange())){
                    ViewCompat.postInvalidateOnAnimation(this)
                }
                stopNestedScroll()
            }

            MotionEvent.ACTION_POINTER_UP ->{
                onSecondaryPointerUp(ev)
            }
        }
        return mIsBeingDragged
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        initVelocityTrackerIfNotExists()
        val vtev = MotionEvent.obtain(event)
        val actionMasked = MotionEventCompat.getActionMasked(event)
        if (actionMasked == MotionEvent.ACTION_DOWN){
            mNestedOffset = 0
        }
        vtev.offsetLocation(0f, mNestedOffset.toFloat())
        when(actionMasked){
            MotionEvent.ACTION_DOWN->{
                mIsBeingDragged = !mScroller.isFinished
                if (mIsBeingDragged && parent != null){
                    parent.requestDisallowInterceptTouchEvent(true)
                }
                if (mIsBeingDragged){
                    mLastFlingValue = 0

                    mScroller.abortAnimation()
                    if (DEBUG){
                        Log.v(TAG, "mScroller.abortAnimation")
                    }
                }


                mLastMotionY = event!!.y.toInt()
                mActivePointerId = event.getPointerId(0)
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
            }
            MotionEvent.ACTION_MOVE-> run {
                val activePointerIndex = event!!.findPointerIndex(mActivePointerId)
                if (activePointerIndex == -1){
                    Log.e(TAG, "Invalid pointerId=$activePointerIndex in onTouchEvent")
                    return@run
                }
                val y = event.getY(activePointerIndex)
                var deltaY = (mLastMotionY - y).toInt()
                if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)){
                    deltaY -= mScrollConsumed[1]
                    vtev.offsetLocation(0f, mScrollOffset[1].toFloat())
                    mNestedOffset += mScrollOffset[1]
                }
                if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop){
                    if (parent != null) parent.requestDisallowInterceptTouchEvent(true)
                    mIsBeingDragged = true
                    if (deltaY > 0){
                        deltaY -= mTouchSlop
                    }else{
                        deltaY += mTouchSlop
                    }
                }

                if (mIsBeingDragged){
                    // Scroll to follow the motion event
                    mLastMotionY = (y - mScrollOffset[1]).toInt()
                    val oldY = scrollY
                    val range = getScrollRange()
                    if (overScrollByCompat(0, deltaY, 0, scrollY, 0, range,
                            0, 0, true)
                            && !hasNestedScrollingParent()){
                        mVelocityTracker!!.clear()
                    }

                    val scrolledDeltaY = scrollY - oldY
                    val unconsumedY = deltaY - scrolledDeltaY
                    if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)){
                        mLastMotionY -= mScrollOffset[1]
                        vtev.offsetLocation(0f, mScrollOffset[1].toFloat())
                        mNestedOffset += mScrollOffset[1]
                    }else{
                        // overscroll edge glows
                    }
                }
            }

            MotionEvent.ACTION_UP-> {
                if (mIsBeingDragged){
                    val velocityTracker = mVelocityTracker
                    velocityTracker!!.computeCurrentVelocity(1000, mMaximumVelocity.toFloat())
                    val initialVelocity = VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId)
                    if (Math.abs(initialVelocity) > mMinimumVelocity){
                        flingWithNestedDispatch(-initialVelocity)
                    }else if (mScroller.springBack(scrollX, scrollY, 0, 0, 0, getScrollRange())){
                        ViewCompat.postInvalidateOnAnimation(this)
                    }
                    mActivePointerId = INVALID_POINTER
                    endDrag()
                }
            }

            MotionEvent.ACTION_CANCEL ->{
                if (mIsBeingDragged){
                    if (mScroller.springBack(scrollX, scrollY, 0, 0, 0, getScrollRange())){
                        ViewCompat.postInvalidateOnAnimation(this)
                    }
                }
                mActivePointerId = INVALID_POINTER
                endDrag()
            }

            MotionEvent.ACTION_POINTER_DOWN->{
                val index = MotionEventCompat.getActionIndex(event)
                mLastMotionY = event!!.getY(index).toInt()
                mActivePointerId = event.getPointerId(index)
            }

            MotionEvent.ACTION_POINTER_UP-> {
                onSecondaryPointerUp(event!!)
                mLastMotionY = event.getY(event.findPointerIndex(mActivePointerId)).toInt()
            }
        }
        if (mVelocityTracker != null){
            mVelocityTracker!!.addMovement(vtev)
        }
        vtev.recycle()
        return mIsBeingDragged
    }

    private fun endDrag() {
        mIsBeingDragged = false
        recycleVelocityTracker()
        stopNestedScroll()
    }

    private fun flingWithNestedDispatch(velocityY: Float) {
   /*     val canFling = (scrollY > 0 || velocityY > 0)
                && (scrollY <= getChildAt(0).measuredHeight || velocityY < 0)*/
        val canFling = true
        if (!dispatchNestedPreFling(0f, velocityY)){
            dispatchNestedFling(0f, velocityY, canFling)
            if (canFling){
                fling(velocityY)
            }
        }
    }

    /**
     * Fling the Scroll View
     * @param velocityY The Initial Velocity in the Y direction.
     */
    fun fling(velocityY: Float) {
        val scrollRange = scrollRangeOfView(getChildAt(0)) + scrollRangeOfView(getChildAt(1))
        mLastFlingValue = 0
        if (DEBUG){
            Log.v(TAG, "fling, and velocityY is $velocityY")
        }
        mScroller.fling(0, 0, 0, velocityY.toInt(), 0, 0, -scrollRange,
                scrollRange, 0, 0)
        ViewCompat.postInvalidateOnAnimation(this)
    }

    override fun computeScroll() {
        if (mScroller.computeScrollOffset()){
            val deltaScrollY = mScroller.currY - mLastFlingValue
            val isFinished = mScroller.isFinished
            if (DEBUG){
                Log.v(TAG, "computeScroll, and deltaScrollY is $deltaScrollY," +
                        " oldValue $mLastFlingValue, isFinished $isFinished")
            }
            mLastFlingValue = mScroller.currY
            fakeScrollBy(deltaScrollY)
            if (deltaScrollY == 0 && !isFinished){
                ViewCompat.postInvalidateOnAnimation(this)
            }
        }
    }

    private fun overScrollByCompat(deltaX: Int, deltaY: Int,
                                   scrollX: Int, scrollY: Int,
                                   scrollRangeX: Int, scrollRangeY: Int,
                                   maxOverScrollX: Int, maxOverScrollY: Int,
                                   isTouchEvent: Boolean): Boolean {
        val canScrollVertical = computeVerticalScrollRange() > computeVerticalScrollExtent()
        fakeScrollBy(deltaY)
        return false
    }

    override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
    }

    fun firstScrollToTop(): Boolean{
        return !getChildAt(0)!!.canScrollVertically(-1) && scrollY <= 0
    }

    fun fakeScrollBy(fakeScrollYDelta: Int){
        if (DEBUG){
            Log.v(TAG, "fakeScrollBy, and fakeScrollYDelta is $fakeScrollYDelta")
        }
        if (fakeScrollYDelta == 0) return
        val first = getChildAt(0)
        val second = getChildAt(1)

        if (fakeScrollYDelta > 0){
            if (!second.canScrollVertically(1) && scrollY >= first.measuredHeight){
                if (DEBUG){
                    Log.v(TAG, "second can't scroll, stop...")
                }
                return
            }
        }else{
            if (!first.canScrollVertically(-1) && scrollY <= 0){
                if (DEBUG){
                    Log.v(TAG, "first can't scroll, stop..")
                }
                return
            }
        }
        if (first.bottom <= scrollY && second.canScrollVertically(fakeScrollYDelta)){
            overScrollByInternal(second, fakeScrollYDelta)
        }else if (second.top - scrollY >= height && first.canScrollVertically(fakeScrollYDelta)){
            overScrollByInternal(first, fakeScrollYDelta)
        }else{
            // 交叉阶段
            if (fakeScrollYDelta > 0){
                // 向上滑动
                val parentScrollY = Math.min(fakeScrollYDelta, first.bottom - scrollY)
                scrollBy(0, parentScrollY)
                val unconsumed = fakeScrollYDelta - parentScrollY
                if (unconsumed > 0){
                    overScrollByInternal(second, unconsumed)
                }
            }else{
                val parentScrollY = Math.max(fakeScrollYDelta, second.top - first.measuredHeight - scrollY)
                scrollBy(0, parentScrollY)
                val unconsumed = fakeScrollYDelta - parentScrollY
                if (unconsumed < 0){
                    overScrollByInternal(first, unconsumed)
                }
            }
        }
        awakenScrollBars()
        onScrollChanged?.invoke()
    }

    private fun overScrollByInternal(view: View, deltaY: Int){
        ViewCompat.startNestedScroll(view, ViewCompat.SCROLL_AXIS_VERTICAL)
        if (view is NestedScrollView){
           if (view is ldk.util.scrollviews.NestedScrollView){
               view.scrollBy(deltaY)
           }else{
               throw IllegalStateException("Not Support NestedScrollView in v4, please use NestedScrollView in my package")
           }
        }
        if (view is RecyclerView){
            view.scrollBy(0, deltaY);
        }
        if (view is WebView){
            if (view is NestedWebView){
                view.scrollBy(deltaY)
            }else{
                throw IllegalStateException("Not Support WebView, used NestedWebView pleased")
            }
        }

        if (view is TwoChildScrollView){
            val offset = view.computeVerticalScrollOffset()
            view.fakeScrollBy(deltaY)
            val consumedScrollY = view.computeVerticalScrollOffset() - offset
            val unConsumedScrollY = deltaY - consumedScrollY
            if (DEBUG){
                Log.v(TAG, "overScrollByInternal, consumedScrollBy $consumedScrollY, unConsumedScrollY is $unConsumedScrollY, and deltaY is $deltaY")
            }
            ViewCompat.postInvalidateOnAnimation(this)
        }
        ViewCompat.stopNestedScroll(view)
    }



    private fun scrollRangeOfView(view: View): Int {
        val result: Int
        if (view is ScrollingView){
            result =  view.computeVerticalScrollRange()
        }else{
            val computeVerticalScrollRange = View::class.java.getDeclaredMethod("computeVerticalScrollRange")
            computeVerticalScrollRange.isAccessible = true
            result =  computeVerticalScrollRange.invoke(view) as Int
        }
        return result
    }

    private fun getScrollRange(): Int {
        return getChildAt(0).measuredHeight + getChildAt(1).measuredHeight
    }

    private fun onSecondaryPointerUp(ev: MotionEvent){
        // copy from NestedScrollView, I'dont know why
        val pointerIndex = (ev.action and MotionEventCompat.ACTION_POINTER_INDEX_MASK) shr  MotionEventCompat.ACTION_POINTER_INDEX_SHIFT
        val pointerId = ev.getPointerId(pointerIndex)
        if (pointerId == mActivePointerId){
            val newPointerIndex = if (pointerIndex == 0) 1 else 0
            mLastMotionY = ev.getY(newPointerIndex).toInt()
            mActivePointerId = ev.getPointerId(newPointerIndex)
            if (mVelocityTracker != null){
                mVelocityTracker!!.clear()
            }
        }
    }

    private fun otherView(view: View): View{
        val first = getChildAt(0)
        val second = getChildAt(1)
        return if (view == first) second else first
    }

    override fun onStartNestedScroll(child: View?, target: View?, nestedScrollAxes: Int): Boolean {
        if (DEBUG){
            Log.v(TAG, "onStartNestedScroll, and nestedScrollAxes $nestedScrollAxes")
        }
        return (nestedScrollAxes and ViewCompat.SCROLL_AXIS_VERTICAL) != 0
    }

    override fun onNestedScrollAccepted(child: View?, target: View?, axes: Int) {
        if (DEBUG){
            Log.v(TAG, "onNestedScrollAccepted")
        }
        mParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes)
        startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
    }

    override fun onStopNestedScroll(child: View?) {
        mParentHelper.onStopNestedScroll(child)
        stopNestedScroll()
    }

    override fun onNestedScroll(target: View?, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int) {
        if (DEBUG){
            Log.v(TAG, "onNestedScroll:  dyConsumed is $dyConsumed, dyUnConsumed is $dyUnconsumed, target is $target")
        }
        if (dyUnconsumed != 0)
            fakeScrollBy(dyUnconsumed)
    }

    override fun onNestedPreScroll(target: View?, dx: Int, dy: Int, consumed: IntArray?) {
        if (DEBUG){
            Log.v(TAG, "onNestedPreScroll, dy is $dy, consumed is $consumed, target is $target")
        }
        dispatchNestedPreScroll(dx, dy, consumed, null)
    }

    override fun onNestedFling(target: View?, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
        return super.onNestedFling(target, velocityX, velocityY, consumed)
    }

    override fun onNestedPreFling(target: View?, velocityX: Float, velocityY: Float): Boolean {
        val result = super.onNestedPreFling(target, velocityX, velocityY)
        if (DEBUG){
            Log.v(TAG, "onNestedPreFling, result is $result")
        }
        return result
    }

    override fun getNestedScrollAxes(): Int {
        return mParentHelper.nestedScrollAxes
    }

    override fun setNestedScrollingEnabled(enabled: Boolean) {
        mChildHelper.isNestedScrollingEnabled = enabled
    }

    override fun isNestedScrollingEnabled(): Boolean {
        return mChildHelper.isNestedScrollingEnabled
    }

    override fun startNestedScroll(axes: Int): Boolean {
        return mChildHelper.startNestedScroll(axes)
    }

    override fun stopNestedScroll() {
        mChildHelper.stopNestedScroll()
    }

    override fun hasNestedScrollingParent(): Boolean {
        return mChildHelper.hasNestedScrollingParent()
    }

    override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?): Boolean {
        return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow)
    }

    override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?): Boolean {
        return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
    }

    override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
        return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed)
    }

    override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
        return mChildHelper.dispatchNestedPreFling(velocityX, velocityY)
    }


}